#include <limits.h>
#include <stdio.h>
#include <string.h>

#include "graph.hh"
#include "construct_greedy_randomized_solution.hh"
#include "local_search_neighborhood_randomly.hh"
#include "local_search_key_path.hh"
#include "utilis.hh"

using namespace std;


void LoadParametersFile(char * parameters_path_folder,
							int  &MAX_K,
							int  &MIN_K,
							int  &STEP_K,

							int  &MAX_ITER,
							int  &MIN_ITER,
							int  &STEP_ITER,

							double  &MAX_BETA,
							double  &MIN_BETA,
							double  &DELTA_BETA,

							double  &MAX_ALPHA,
							double  &MIN_ALPHA,
							double  &DELTA_ALPHA,

							int  &MAX_SIZE_POOL,
							int  &MIN_SIZE_POOL,
							int  &STEP_SIZE_POOL,

							int  &MAX_TEST) {

	ifstream file(parameters_path_folder);
	string line;
	float _value_float;

	//cout << "1111111111111" << endl;

	if (file.is_open() && file.good()) {

		getline(file, line);
		sscanf(line.c_str(),"MAX_K %d", &MAX_K);
		getline(file, line);
		sscanf(line.c_str(),"MIN_K %d", &MIN_K);
		getline(file, line);
		sscanf(line.c_str(),"STEP_K %d", &STEP_K);

		getline(file, line);

		getline(file, line);
		sscanf(line.c_str(),"MAX_ITER %d", &MAX_ITER);
		getline(file, line);
		sscanf(line.c_str(),"MIN_ITER %d", &MIN_ITER);
		getline(file, line);
		sscanf(line.c_str(),"STEP_ITER %d", &STEP_ITER);

		getline(file, line);

		getline(file, line);
		sscanf(line.c_str(),"MAX_BETA %f", &_value_float); MAX_BETA = _value_float;
		getline(file, line);
		sscanf(line.c_str(),"MIN_BETA %f", & _value_float); MIN_BETA = _value_float;
		getline(file, line);
		sscanf(line.c_str(),"DELTA_BETA %f", & _value_float); DELTA_BETA = _value_float;

		getline(file, line);

		getline(file, line);
		sscanf(line.c_str(),"MAX_ALPHA %f", &_value_float); MAX_ALPHA = _value_float;
		getline(file, line);
		sscanf(line.c_str(),"MIN_ALPHA %f", &_value_float); MIN_ALPHA= _value_float;
		getline(file, line);
		sscanf(line.c_str(),"DELTA_ALPHA %f", &_value_float); DELTA_ALPHA = _value_float;

		getline(file, line);

		getline(file, line);
		sscanf(line.c_str(),"MAX_SIZE_POOL %d", &MAX_SIZE_POOL);
		getline(file, line);
		sscanf(line.c_str(),"MIN_SIZE_POOL %d", &MIN_SIZE_POOL);
		getline(file, line);
		sscanf(line.c_str(),"STEP_SIZE_POOL %d", &STEP_SIZE_POOL);

		getline(file, line);

		getline(file, line);
		sscanf(line.c_str(),"MAX_TEST  %d", &MAX_TEST);
	}
	else
		cout << "Unable to open file" << endl;

	//cout << "222222222222222" << endl;
}

int calibrator(int argc, char *argv[]) {

	/*cout << argc << endl;

	cout << argv[0] << endl;
	cout << argv[1] << endl;
	cout << argv[2] << endl;
	cout << argv[3] << endl;*/

	if(argc < 4) {
		cout << "[ERROR]: Invalid arguments" << endl;
		cout << "[INFO]: ./gspdc_grasp <parameters_path_file> <instances_path_folder>  <results_path_folder>" << endl;
		return -1;
	}

	int  MAX_K;
	int  MIN_K;
	int  STEP_K;

	int  MAX_ITER;
	int  MIN_ITER;
	int  STEP_ITER;

	double  MAX_BETA;
	double  MIN_BETA;
	double  DELTA_BETA;

	double  MAX_ALPHA;
	double  MIN_ALPHA;
	double  DELTA_ALPHA;

	int  MAX_SIZE_POOL;
	int  MIN_SIZE_POOL;
	int  STEP_SIZE_POOL;

	int  MAX_TEST;



	LoadParametersFile(argv[1],
						MAX_K,
						MIN_K,
						STEP_K,

						MAX_ITER,
						MIN_ITER,
						STEP_ITER,

						MAX_BETA,
						MIN_BETA,
						DELTA_BETA,

						MAX_ALPHA,
						MIN_ALPHA,
						DELTA_ALPHA,

						MAX_SIZE_POOL,
						MIN_SIZE_POOL,
						STEP_SIZE_POOL,

						MAX_TEST);



	/*cout << MAX_K << endl;
	cout << MIN_K << endl;
	cout << STEP_K << endl;

	cout << endl;

	cout << MAX_ITER << endl;
	cout << MIN_ITER << endl;
	cout << STEP_ITER << endl;

	cout << endl;

	cout << MAX_BETA << endl;
	cout << MIN_BETA << endl;
	cout << DELTA_BETA << endl;

	cout << endl;

	cout << MAX_ALPHA << endl;
	cout << MIN_ALPHA << endl;
	cout << DELTA_ALPHA << endl;

	cout << endl;

	cout << MAX_SIZE_POOL << endl;
	cout << MIN_SIZE_POOL << endl;
	cout << STEP_SIZE_POOL << endl;

	cout << endl;

	cout << MAX_TEST << endl;*/


	// initialize random seed
	srand(time(NULL));

	int k_best = 0;
	int max_iter_best = 0;
	double beta_best = 0;
	double alpha_best = 0;
	int size_pool_best = 0;
	char buffer[256];

	//cout << "33333333333333333333" << endl;

	for(int nb_test = 0; nb_test<MAX_TEST; nb_test++) {
		char path_file_in[256];
		char path_file_out[256];

		Graph * G_best_best = new Graph();
		PathMatrix * PM_G_best_best = new PathMatrix();
		int G_best_best_cost = INT_MAX;

		strcpy(path_file_in, argv[2]);
		strcat(path_file_in, "test");
		sprintf(buffer, "%d", nb_test);
		strcat(path_file_in, buffer);



		for(int k= MIN_K; k<=MAX_K; k+=STEP_K) {
			for(int max_iter= MIN_ITER; max_iter<=MAX_ITER; max_iter+=STEP_ITER) {
				for(int h= 0; h<DELTA_BETA; h++) {
					double beta = MIN_BETA + ((MAX_BETA - MIN_BETA)/DELTA_BETA)*h;
					for(int g= 0; g<DELTA_ALPHA; g++) {
						double alpha = MIN_ALPHA + ((MAX_ALPHA - MIN_ALPHA)/DELTA_ALPHA)*g;
						for(int size_pool= MIN_SIZE_POOL; size_pool<=MAX_SIZE_POOL; size_pool+=STEP_SIZE_POOL) {

							//cout << nb_test << " " << k << "  " << max_iter << "  " << beta << "  " << alpha << "  " << size_pool << endl;

							//cout << path_file_in << endl;

							Graph * Problem = new Graph(path_file_in);
							Graph * G_best = new Graph();
							PathMatrix * PM_G_best = new PathMatrix();
							int G_best_cost = INT_MAX;

							pair<Graph*, PathMatrix*> * G_P;

							for (int i = 0; i < max_iter; i++) {
								G_P = ConstructGreedyRandomizedSolution(Problem, k);

								if(G_P) { // Si es una solucion factible
						RETRY:
									LocalSearchNeighborhoodRandomly(Problem, k, G_P->first, G_P->second, alpha, beta, size_pool);
									if (G_P->first->Cost() < G_best_cost) {
										delete G_best;
										delete PM_G_best;

										G_best = new Graph(G_P->first);
										G_best_cost = G_P->first->Cost();
										PM_G_best = new PathMatrix(G_P->second);
									}

									LocalSearchKeyPath(Problem, G_P->first, G_P->second);
									if (G_P->first->Cost() < G_best_cost) {
										delete G_best;
										delete PM_G_best;

										G_best = new Graph(G_P->first);
										G_best_cost = G_P->first->Cost();
										PM_G_best = new PathMatrix(G_P->second);
										goto RETRY;
									}

									DeletePair(G_P);
								}
							}

							if(G_best->Cost() < G_best_best_cost) {

								k_best = k;
								max_iter_best = max_iter;
								beta_best = beta;
								alpha_best = alpha;
								size_pool_best = size_pool;

								delete G_best_best;
								delete PM_G_best_best;

								G_best_best = new Graph(G_best);
								PM_G_best_best = new PathMatrix(PM_G_best);
								G_best_best_cost = G_best_best->Cost();

							}

							delete PM_G_best;
							delete G_best;
							delete Problem;
						}
					}
				}
			}
		}

		strcpy(path_file_out, argv[3]);
		strcat(path_file_out, "test");
		sprintf(buffer, "%d", nb_test);
		strcat(path_file_out, buffer);

		G_best_best->Dump(path_file_out);

		cout << nb_test << " " << k_best << "  " << max_iter_best << "  " << beta_best << "  " << alpha_best << "  " << size_pool_best << "  " << G_best_best_cost << endl;

		delete G_best_best;
		delete PM_G_best_best;

	}
	return 0;
}
